package com.sum.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.setting.dialect.Props;
import com.sum.entry.Cell;
import com.sum.util.CellUtil;
import com.sum.util.SettingUtil;
import com.sum.util.ToolUtil;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;

import java.awt.*;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * SumController
 *
 * @author shuzh
 */
public class SumController {


    @FXML
    private TabPane tabPane;

    @FXML
    private Tab configTab;

    @FXML
    private TextField targetFile;

    @FXML
    private TextArea cellRange;

    @FXML
    private Button chooseButton1;

    @FXML
    private Button chooseButton2;

    @FXML
    private TextField sourcePath;

    @FXML
    private Tab resultTab;

    @FXML
    private TextArea console;

    @FXML
    private Button openDirButton;

    @FXML
    private Button openFileButton;

    @FXML
    private Button closeButton;

    @FXML
    private Button startButton;

    @FXML
    private Label processedFileNum;

    @FXML
    private Label allFileNum;

    @FXML
    private Label runStatus;


    private Set<Cell> cellSet;

    private File[] files;




    @FXML
    public void initialize() {
        resultTab.setDisable(true);
        openDirButton.setVisible(false);
        openFileButton.setVisible(false);
        initConfig();
    }


    /**
     * 初始化配置信息
     */
    private void initConfig() {
        String homePath = System.getProperty("user.dir") + "\\";
        Props props = new Props(homePath + "config.properties", "utf8");

        String sourcePathValue = props.getStr(SettingUtil.Key.SOURCE_PATH, SettingUtil.DEFAULT_SOURCE_PATH);
        sourcePathValue = sourcePathValue.replace("/", "\\");
        sourcePath.setText(String.format("%s%s",
                sourcePathValue.contains(":") ? StringUtils.EMPTY : homePath, sourcePathValue));

        String targetFileValue = props.getStr(SettingUtil.Key.TARGET_FILE, SettingUtil.DEFAULT_TARGET_FILE);
        targetFileValue = targetFileValue.replace("/", "\\");
        targetFile.setText(String.format("%s%s",
                targetFileValue.contains(":") ? StringUtils.EMPTY : homePath, targetFileValue));

        cellRange.setText(props.getStr(SettingUtil.Key.CELL_RANGE, SettingUtil.DEFAULT_CELL_RANGE));
    }

    /**
     * 初始化结果数据
     */
    private void initResult() {
        allFileNum.setText(StringUtils.EMPTY);
        processedFileNum.setText(StringUtils.EMPTY);
        console.setText(StringUtils.EMPTY);
    }

    @FXML
    void chooseButton1Event(ActionEvent event) {
        try {
            DirectoryChooser directoryChooser = new DirectoryChooser();
            String path = StringUtils.isNotEmpty(sourcePath.getText()) ?
                    sourcePath.getText() : System.getProperty("user.dir");
            directoryChooser.setInitialDirectory(new File(path));
            File file = directoryChooser.showDialog(null);
            if (file != null) {
                sourcePath.setText(file.getAbsolutePath());
            }
        } catch (Exception ignored) {}
    }

    @FXML
    void chooseButton2Event(ActionEvent event) {
        try {
            FileChooser fileChooser = new FileChooser();

            // 打开的目录
            File openDir = null;
            String fileName = ".xls";
            if (StringUtils.isNotEmpty(targetFile.getText())) {
                openDir = new File(targetFile.getText());
                fileName = openDir.getName();
                if (openDir.isFile() || openDir.getName().contains(".xls")) {
                    openDir = openDir.getParentFile();
                }
            } else {
                openDir = new File(System.getProperty("user.dir"));
            }
            fileChooser.setInitialDirectory(openDir);
            fileChooser.setInitialFileName(fileName);

            // 扩展名过滤
            fileChooser.getExtensionFilters().addAll(
                    new FileChooser.ExtensionFilter("xls", "*.xls"),
                    new FileChooser.ExtensionFilter("xlsx", "*.xlsx")
            );

            File file = fileChooser.showSaveDialog(null);
            if (file != null) {
                targetFile.setText(file.getAbsolutePath());
            }
        } catch (Exception ignored) {}
    }

    @FXML
    void sourcePathEvent(ActionEvent event) {

    }

    @FXML
    void targetFileEvent(ActionEvent event) {
    }

    @FXML
    void startButtonEvent(ActionEvent event) {
        if (preCheck()) {
            initResult();
            runStatus.setText("运行中");
            runStatus.setStyle("-fx-text-fill: black;");
            openFileButton.setVisible(false);
            openDirButton.setVisible(false);
            resultTab.setDisable(false);
            tabPane.getSelectionModel().select(resultTab);
            if (sumHandle()) {
                openFileButton.setVisible(true);
                openDirButton.setVisible(true);
                runStatus.setText("已完成");
                runStatus.setStyle("-fx-text-fill: green;");
            }
        }
    }

    /**
     * 前置检查
     *
     * @return
     */
    private boolean preCheck() {
        // 解析要处理哪些单元格
        if (StringUtils.isEmpty(cellRange.getText())) {
            ToolUtil.errorAlert("单元格汇总范围未指定，请填写【单元格范围】！");
            return false;
        }

        cellSet = CellUtil.getCellSet(cellRange.getText());
        if (ObjectUtil.isEmpty(cellSet)) {
            ToolUtil.errorAlert("单元格范围解析为空，请重新填写【单元格范围】！");
            return false;
        }

        // 获取源文件
        File sourceDir = new File(sourcePath.getText());
        if (!sourceDir.exists()) {
            ToolUtil.errorAlert("单元格范围解析为空，请重新填写【单元格范围】！");
            return false;
        }

        files = sourceDir.listFiles(fileName -> fileName.getName().endsWith(".xls")
                || fileName.getName().endsWith(".xlsx"));
        if (ObjectUtil.isEmpty(files)) {
            ToolUtil.errorAlert(String.format("数据文件夹【%s】中未找到需汇总的原始Excel文件！", sourceDir.getAbsolutePath()));
            return false;
        }

        if (StringUtils.isEmpty(targetFile.getText())) {
            ToolUtil.errorAlert("未指定输出文件！");
            return false;
        }

        return true;
    }


    /**
     * 正式汇总
     *
     * @return
     */
    private boolean sumHandle() {

        console.appendText("开始处理......\n");
        allFileNum.setText(String.valueOf(files.length));

        // 输出文件
        File outputFile = new File(targetFile.getText());
        if (!outputFile.getParentFile().exists()) {
            outputFile.getParentFile().mkdirs();
        }

        Map<Cell, Integer> map = new LinkedHashMap<>();
        for (int i = 0; i < files.length; ++i) {
            File file = files[i];
            // 如果输出文件不存在，则用输入文件中的某个文件，拷贝过去。因为所有文件格式一样，数据不一样
            if (!outputFile.exists()) {
                FileUtil.copy(file, outputFile, false);
            }

            // 读取各个单元格，并计算不同文件下各单元格总和
            ExcelReader reader = ExcelUtil.getReader(file);
            for (Cell cell : cellSet) {
                Object o = reader.readCellValue(cell.getColIndex() - 1, cell.getRowIndex() - 1);
                if (o != null && StringUtils.isNotEmpty(String.valueOf(o))) {
                    int num = 0;
                    try {
                        num = Integer.parseInt(String.valueOf(o));
                    } catch (NumberFormatException e) {
                        console.appendText(String.format("【警告】- 文件【%s】中单元格【%s】解析错误，值为【%s】！\n", file.getName(), cell.getName(), String.valueOf(o)));
                        continue;
                    }

                    if (map.containsKey(cell)) {
                        map.put(cell, map.get(cell) + num);
                    } else {
                        map.put(cell, num);
                    }
                }
            }

            processedFileNum.setText(String.valueOf(i + 1));
        }

        // 写文件
        ExcelWriter writer = ExcelUtil.getWriter(outputFile);
        // 样式 - 右对齐，上下居中
        CellStyle style = writer.getCellStyle();
        style.setAlignment(HorizontalAlignment.RIGHT);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        // 遍历填充数字
        for (Map.Entry<Cell, Integer> entry : map.entrySet()) {
            Cell cell = entry.getKey();
            // api中列与行索引从0开始
            int x = cell.getColIndex() - 1;
            int y = cell.getRowIndex() - 1;
            // 设置单元格格式
            writer.setStyle(style, x, y);
            // 设置单元格的值
            writer.writeCellValue(x, y, entry.getValue());
        }
        writer.close();

        console.appendText(String.format("已完成汇总工作，汇总文件位置：【%s】", targetFile.getText()));

        return true;
    }


    @SneakyThrows
    @FXML
    void openDirButtonEvent(ActionEvent event) {
        Desktop desktop = Desktop.getDesktop();
        File file = new File(targetFile.getText());
        desktop.open(file.getParentFile());
    }

    @SneakyThrows
    @FXML
    void openFileButtonEvent(ActionEvent event) {
        Desktop desktop = Desktop.getDesktop();
        desktop.open(new File(targetFile.getText()));
    }

    @FXML
    void closeButtonEvent(ActionEvent event) {
        System.exit(0);
    }

}
